
#
# PNG has a signature with 8 octects: 89 50 4e 47 0d 0a 1a 0a
#
# and each chunk has the layout:
#
# +--------+------+------+-----+
# | LENGTH | TYPE | DATA | CRC |
# +--------+------+------+-----+
#
# or
#
# +--------+------+-----+
# | LENGTH | TYPE | CRC |
# +--------+------+-----+
#

"""\
The formatter supports PNG format.

More information about PNG and its specification can refer to \
http://www.w3.org/TR/PNG/.
"""
__version__ = "1.10"

__aof__ = ('Portable Network Graphics', 'PNG')
__extension__ = (('Portable Netowrk Graphics Files', ('*.png',)),)


class _PngDecoder:

    def Execute(self, source, target, notify, **kws):
        PNG_HEADER = (0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a)

        def _checkString(s1, s2):
            if len(s1) == len(s2):
                for k, c in enumerate(s1):
                    if ord(c) != s2[k]:
                        break
                else:
                    return True

            return False

        entry = target.getEntry()
        start = kws.get('start', 0)
        size = len(PNG_HEADER)
        header = source.read(size)
        if not _checkString(header, PNG_HEADER):
            return False

        entry.append(target.newItemObject('Signature', header,
                     field=target.newFieldObject(start, size)))
        kws['offset'] = size

        _BLOCK = (
            ('Len', 4, 'decimal,export'),
            ('Chunk', 4, 'string,export'),
            ('Data', "$0", 'eval'),
            ('CRC', 4, 'value')
        )

        ret = True
        size = len(source)
        target.setEndian('big-endian', kws)
        while ret and kws['offset'] < size:
            ret, objectp, consumed, _, exported = target.parse(
                None, _BLOCK, afile=source, **kws)
            if ret:
                objectp.update(subject=exported[1])
                entry.append(objectp)
                kws['offset'] += consumed

        return ret and kws['offset'] > len(PNG_HEADER)


def fmtService():
    return _PngDecoder, 'picture'
